package com.whfc.common.push;

import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jiguang.common.resp.DefaultResult;
import cn.jiguang.common.utils.Preconditions;
import cn.jiguang.common.utils.StringUtils;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Message;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 极光推送 API
 *
 * @author qzexing
 * @version 1.0
 * @date 2021-03-30 17:04
 */
public class JPushApi {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 极光推送客户端
     */
    private final JPushClient jPushClient;

    /**
     * 是否生产环境
     */
    private final boolean apnsProduction;

    /**
     * 推送平台  默认推送全部
     */
    private final JPushPlatform platform;

    /**
     * 推送消息类型
     */
    private final JPushType pushType;

    /**
     * 基本API 默认推送全平台，推送类型为通知
     *
     * @param appKey         App Key
     * @param masterSecret   secret
     * @param apnsProduction 是否生产环境
     */
    public JPushApi(String appKey, String masterSecret, boolean apnsProduction) {
        jPushClient = new JPushClient(masterSecret, appKey);
        this.apnsProduction = apnsProduction;
        this.platform = JPushPlatform.ALL;
        this.pushType = JPushType.NOTIFICATION;
    }

    /**
     * 可配置平台API  推送类型为通知
     *
     * @param appKey         App Key
     * @param masterSecret   secret
     * @param apnsProduction 是否生产环境
     * @param platform       平台
     */
    public JPushApi(String appKey, String masterSecret, boolean apnsProduction, JPushPlatform platform) {
        jPushClient = new JPushClient(masterSecret, appKey);
        this.apnsProduction = apnsProduction;
        this.platform = platform;
        this.pushType = JPushType.NOTIFICATION;
    }

    /**
     * 可配置平台以及推送类型API
     *
     * @param appKey         App Key
     * @param masterSecret   secret
     * @param apnsProduction 是否生产环境
     * @param platform       平台
     * @param pushType       推送类型
     */
    public JPushApi(String appKey, String masterSecret, boolean apnsProduction, JPushPlatform platform, JPushType pushType) {
        jPushClient = new JPushClient(masterSecret, appKey);
        this.apnsProduction = apnsProduction;
        this.platform = platform;
        this.pushType = pushType;
    }

    /**
     * 单个设备ID推送
     *
     * @param registrationId 设备Registration ID
     * @param pm             消息
     * @return 成功时返回消息ID
     */
    public Long pushToDevice(String registrationId, JPushMessage pm) {
        Preconditions.checkArgument(!StringUtils.isEmpty(registrationId), "设备Registration ID为空");
        return executePush(createPushPayload(pm, Audience.registrationId(registrationId)));
    }

    /**
     * 多个设备ID推送
     *
     * @param registrationIdList 设备Registration ID列表
     * @param pm                 消息
     * @return 成功时返回消息ID
     */
    public Long pushToDevices(List<String> registrationIdList, JPushMessage pm) {
        Preconditions.checkArgument(!CollectionUtils.isEmpty(registrationIdList), "设备Registration ID为空");
        Preconditions.checkArgument(registrationIdList.size() <= 1000, "设备Registration ID不超过1000个");
        return executePush(createPushPayload(pm, Audience.registrationId(registrationIdList)));
    }

    /**
     * 根据别名推送
     *
     * @param aliasList 别名列表
     * @param pm        消息
     * @return 成功时返回消息ID
     */
    public Long pushToAliases(List<String> aliasList, JPushMessage pm) {
        Preconditions.checkArgument(!CollectionUtils.isEmpty(aliasList), "别名为空");
        Preconditions.checkArgument(aliasList.size() <= 1000, "别名不超过1000个");
        return executePush(createPushPayload(pm, Audience.alias(aliasList)));
    }

    /**
     * 根据标签推送
     *
     * @param tagsList 标签列表
     * @param pm       消息
     * @return 成功时返回消息ID
     */
    public Long pushToTags(List<String> tagsList, JPushMessage pm) {
        Preconditions.checkArgument(!CollectionUtils.isEmpty(tagsList), "标签为空");
        Preconditions.checkArgument(tagsList.size() <= 1000, "标签不超过1000个");
        return executePush(createPushPayload(pm, Audience.tag(tagsList)));
    }

    /**
     * 推送给所有客户端
     *
     * @param pm 消息
     * @return 成功时返回消息ID
     */
    public Long pushToAll(JPushMessage pm) {
        return executePush(createPushPayload(pm, Audience.all()));
    }


    /**
     * 删除别名
     *
     * @param aliasList 待删除的别名列表
     */
    public void deleteAlias(List<String> aliasList) {
        if (CollectionUtils.isEmpty(aliasList)) {
            return;
        }
        aliasList.forEach(a -> {
            if (StringUtils.isEmpty(a)) {
                return;
            }
            try {
                DefaultResult result = jPushClient.deleteAlias(a, null);
                logger.info("删除别名接口返回码: {}, alias: {}", result != null ? result.getResponseCode() : null, a);
            } catch (APIConnectionException | APIRequestException e) {
                logger.error("删除别名时发生异常! alias:{}", a, e);
            }
        });
    }

    /**
     * 执行推送
     *
     * @param payload 消息体
     * @return 成功时返回消息ID
     */
    private Long executePush(PushPayload payload) {
        logger.info("推送消息体: {}", payload.toJSON());
        try {
            PushResult result = jPushClient.sendPush(payload);
            if (result == null) {
                return null;
            }
            if (200 == result.getResponseCode()) {
                logger.info("消息推送成功，消息ID: {}", result.msg_id);
                return result.msg_id;
            }
            logger.warn("消息推送失败，ResponseCode={}", result.getResponseCode());
        } catch (Exception e) {
            logger.warn("消息推送失败", e);
        }
        return null;
    }


    private PushPayload createPushPayload(JPushMessage pm, Audience audience) {
        PushPayload.Builder builder = PushPayload.newBuilder();
        Platform jPlatForm = Platform.all();
        Notification.Builder notificationBuilder = Notification.newBuilder().setAlert(pm.getContent());
        if (JPushPlatform.ANDROID.equals(platform)) {
            jPlatForm = Platform.android();
            notificationBuilder.addPlatformNotification(AndroidNotification.newBuilder()
                    .setTitle(pm.getTitle()).addExtras(pm.getExtras()).build());
        } else if (JPushPlatform.IOS.equals(platform)) {
            jPlatForm = Platform.ios();
            notificationBuilder.addPlatformNotification(IosNotification.newBuilder()
                    .setSound("default").addExtras(pm.getExtras()).build());
        }
        builder.setPlatform(jPlatForm);
        builder.setAudience(audience);
        builder.setOptions(Options.newBuilder().setApnsProduction(apnsProduction).build());
        if (JPushType.MESSAGE.equals(pushType)) {
            builder.setMessage(
                    Message.newBuilder().setTitle(pm.getTitle())
                            .setMsgContent(pm.getContent())
                            .addExtras(pm.getExtras())
                            .build()
            ).build();
        } else {
            builder.setNotification(notificationBuilder.build());
        }
        return builder.build();
    }

    public static void main(String[] args) {
        String appKey = "2d3190fbd10bdc7e3b7ce1a7";
        String masterSecret = "6f6ddd7c5bdf71dae5291038";
        JPushApi jPushApi = new JPushApi(appKey, masterSecret, false, JPushPlatform.ANDROID, JPushType.MESSAGE);
        String registrationId = "1507bfd3f7687c7b871";
        JPushMessage message = new JPushMessage();
        message.setTitle("test");
        message.setContent("风潮物联测试");
        Map<String, String> map = new HashMap<>();
        map.put("strRoomId", "666888");
        message.setExtras(map);
        jPushApi.pushToDevice(registrationId,message);
    }

}
